package com.martin.lib_base.ui.screen

import androidx.compose.foundation.Image
import androidx.compose.foundation.gestures.FlingBehavior
import androidx.compose.foundation.gestures.ScrollableDefaults
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.BoxScope
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.LazyItemScope
import androidx.compose.foundation.lazy.LazyListState
import androidx.compose.foundation.lazy.grid.GridCells
import androidx.compose.foundation.lazy.grid.GridItemSpan
import androidx.compose.foundation.lazy.grid.LazyGridItemScope
import androidx.compose.foundation.lazy.grid.LazyVerticalGrid
import androidx.compose.foundation.lazy.grid.items
import androidx.compose.foundation.lazy.items
import androidx.compose.foundation.lazy.rememberLazyListState
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.material3.pulltorefresh.PullToRefreshBox
import androidx.compose.material3.pulltorefresh.PullToRefreshDefaults
import androidx.compose.material3.pulltorefresh.PullToRefreshState
import androidx.compose.material3.pulltorefresh.rememberPullToRefreshState
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.input.nestedscroll.nestedScroll
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.dp
import com.martin.lib_base.R
import com.martin.lib_base.interfaces.IItemKey
import com.martin.lib_base.interfaces.IItemType
import com.martin.lib_base.ktx.toJson
import com.martin.lib_base.model.PageModel
import com.martin.lib_base.ui.theme.ColorPrimary

/**
 * @author：孟凡华
 * @date：2023/6/28
 * @desc：
 */

/**
 * 通用刷新列表
 * @param pageModel 分页数据模型
 * @param typeItemMap 类型与Item的映射
 * @param modifier Modifier
 */
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun CommonRefreshColumn(
    // 分页数据模型
    pageModel: PageModel,
    // 类型
    typeItemMap: Map<Int, @Composable LazyItemScope.(item: Any) -> Unit>,
    // [LazyColumn]的修饰符
    modifier: Modifier = Modifier,
    // 加载更多布局
    loadMore: @Composable () -> Unit? = { CommonLoadMore() },
    state: LazyListState = rememberLazyListState(),
    contentPadding: PaddingValues = PaddingValues(0.dp),
    reverseLayout: Boolean = false,
    verticalArrangement: Arrangement.Vertical =
        if (!reverseLayout) Arrangement.Top else Arrangement.Bottom,
    horizontalAlignment: Alignment.Horizontal = Alignment.Start,
    flingBehavior: FlingBehavior = ScrollableDefaults.flingBehavior(),
    userScrollEnabled: Boolean = true,
    userKey: Boolean = false,
    header: @Composable (() -> Unit)? = null,
    footer: @Composable (() -> Unit)? = null,
) {
    // 刷新状态
    val refreshState = createRefreshState(pageModel)
    // 数据
    val items = pageModel.dataList
    // 是否展示空布局
    val showEmpty = pageModel.showEmpty.value
    // 是否有更多数据
    val haveMore = pageModel.haveMore.value

    PullToRefreshBox(
        isRefreshing = pageModel.refreshing.value,
        onRefresh = pageModel::refresh,
        modifier = Modifier
            .fillMaxSize()
    ) {
        LazyColumn(
            modifier = Modifier
                .fillMaxSize()
                .then(modifier),
            state = state,
            contentPadding = contentPadding,
            reverseLayout = reverseLayout,
            verticalArrangement = verticalArrangement,
            horizontalAlignment = horizontalAlignment,
            flingBehavior = flingBehavior,
            userScrollEnabled = userScrollEnabled
        ) {
            // 头部布局
            if (header != null) {
                item {
                    header()
                }
            }

            // 数据布局
            items(
                // 数据
                items = items,
                // key
                key = if (userKey) {
                    { getItemKey(it) }
                } else {
                    null
                },
                // 内容类型
                contentType = { getItemType(it) }
            ) {
                // 内容
                typeItemMap[getItemType(it)]?.invoke(this, it)
            }

            // 空布局 (数据为空时显示,需要手动添加 typeItemMap[ITypeBean.ITEM_TYPE_EMPTY])
            if (showEmpty && typeItemMap.containsKey(IItemType.ITEM_TYPE_EMPTY)) {
                item(key = IItemType.ITEM_TYPE_EMPTY, contentType = IItemType.ITEM_TYPE_EMPTY) {
                    typeItemMap[IItemType.ITEM_TYPE_EMPTY]?.invoke(this, "")
                }
            }

            // 底部布局
            if (footer != null) {
                item {
                    footer()
                }
            }

            // 加载更多布局
            if (haveMore) {
                item(key = IItemType.ITEM_TYPE_MORE, contentType = IItemType.ITEM_TYPE_MORE) {
                    // 展示布局
                    loadMore()
                    // 加载更多
                    LaunchedEffect(Unit) {
                        pageModel.loadMore()
                    }
                }
            }
        }
    }
}

/**
 * 通用刷新表格
 */
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun CommonRefreshVerticalGrid(
    pageModel: PageModel,
    // 类型
    typeItemMap: Map<Int, @Composable LazyGridItemScope.(item: Any) -> Unit>,
    // 列描述
    columns: GridCells,
    // [LazyColumn]的修饰符
    modifier: Modifier = Modifier,
    // 加载更多布局
    LoadMore: @Composable () -> Unit? = { CommonLoadMore() },
    // 水平排列方式
    horizontalArrangement: Arrangement.Horizontal = Arrangement.Start,
    // 垂直排列方式
    reverseLayout: Boolean = false,
    verticalArrangement: Arrangement.Vertical =
        if (!reverseLayout) Arrangement.Top else Arrangement.Bottom,
    header: @Composable (() -> Unit)? = null,
    footer: @Composable (() -> Unit)? = null,
    contentPadding: PaddingValues = PaddingValues(0.dp),
    userKey: Boolean = false,
) {
    // 刷新状态
    val refreshState = createRefreshState(pageModel)
    // 数据
    val items = pageModel.dataList
    // 是否展示空布局
    val showEmpty = pageModel.showEmpty.value
    // 是否有更多数据
    val haveMore = pageModel.haveMore.value

    PullToRefreshBox(
        isRefreshing = pageModel.refreshing.value,
        onRefresh = pageModel::refresh,
        modifier = Modifier
            .fillMaxSize()
    ) {
        LazyVerticalGrid(
            columns = columns,
            modifier = modifier,
            horizontalArrangement = horizontalArrangement,
            verticalArrangement = verticalArrangement,
            contentPadding = contentPadding,
        ) {
            if (header != null) {
                item(
                    key = IItemType.ITEM_TYPE_HEADER,
                    contentType = IItemType.ITEM_TYPE_HEADER,
                    span = {
                        GridItemSpan(maxLineSpan)
                    }
                ) {
                    header()
                }
            }

            items(
                // 数据
                items = items,
                // key
                key = if (userKey) {
                    { getItemKey(it) }
                } else {
                    null
                },
                // 内容类型
                contentType = { getItemType(it) }
            ) {
                // 内容
                typeItemMap[getItemType(it)]?.invoke(this, it)
            }

            // 空布局 (数据为空时显示,需要手动添加 typeItemMap[ITypeBean.ITEM_TYPE_EMPTY])
            if (showEmpty && typeItemMap.containsKey(IItemType.ITEM_TYPE_EMPTY)) {
                item(
                    key = IItemType.ITEM_TYPE_MORE,
                    contentType = IItemType.ITEM_TYPE_MORE,
                    span = {
                        GridItemSpan(maxLineSpan)
                    }
                ) {
                    typeItemMap[IItemType.ITEM_TYPE_EMPTY]?.invoke(this, "")
                }
            }

            if (footer != null) {
                item(
                    key = IItemType.ITEM_TYPE_FOOTER,
                    contentType = IItemType.ITEM_TYPE_FOOTER,
                    span = {
                        GridItemSpan(maxLineSpan)
                    }
                ) {
                    footer()
                }
            }

            // 加载更多布局
            if (haveMore) {
                item(
                    key = IItemType.ITEM_TYPE_MORE,
                    contentType = IItemType.ITEM_TYPE_MORE,
                    span = {
                        GridItemSpan(maxLineSpan)
                    }
                ) {
                    // lottie动画
                    LoadMore()
                    // 加载更多
                    LaunchedEffect(Unit) {
                        pageModel.loadMore()
                    }
                }
            }
        }
    }
}

@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun CommonRefreshBox(
    modifier: Modifier = Modifier,
    refreshing: Boolean,
    onRefresh: () -> Unit,
    refreshEnabled: Boolean = true,
    /**
     * 必须可滑动
     * Modifier.verticalScroll()
     */
    content: @Composable BoxScope.() -> Unit,
) {
    val refreshState = rememberPullToRefreshState()
    // 监听刷新状态
    LaunchedEffect(refreshing) {
        if (refreshState.isAnimating != refreshing) {
            if (refreshing) {
                refreshState.animateToThreshold()
            } else {
                refreshState.animateToHidden()
            }
        }
    }
    LaunchedEffect(refreshState.isAnimating) {
        if (refreshState.isAnimating) {
            onRefresh()
        }
    }

    PullToRefreshBox(
        isRefreshing = refreshing,
        onRefresh = onRefresh,
        state = refreshState,
        modifier = modifier
    ) {
        content()
    }
}

@Composable
@OptIn(ExperimentalMaterial3Api::class)
private fun BoxScope.RefreshIndicator(
    refreshState: PullToRefreshState,
) {

}


/**
 * 通用加载更多布局
 */
@Composable
fun CommonLoadMore() {
    Center(
        modifier = Modifier
            .fillMaxWidth()
            .height(60.dp)
    ) {
        Text(text = "加载中...")
    }
}

/**
 * 通用空布局
 */
@Composable
fun CommonEmpty(
    message: String = "暂无数据",
    icon: Int = R.drawable.img_empty_data,
    paddingTop: Dp = 100.dp,
) {
    // lottie动画
    Box(
        modifier = Modifier
            .fillMaxSize()
    ) {
        Column(
            horizontalAlignment = Alignment.CenterHorizontally,
            modifier = Modifier
                .fillMaxSize()
        ) {
            Image(
                painter = painterResource(id = icon),
                contentDescription = null,
                modifier = Modifier
                    .padding(top = paddingTop)
                    .size(200.dp)
            )
            Text(
                text = message,
                style = MaterialTheme.typography.labelLarge,
                color = Color.Gray
            )
        }
    }
}

/**
 * 创建刷新状态
 */
@OptIn(ExperimentalMaterial3Api::class)
@Composable
private fun createRefreshState(pageModel: PageModel): PullToRefreshState {
    val enable = pageModel.refreshEnabled.value
    val refreshState = rememberPullToRefreshState()
    // 监听刷新状态
    val refreshing = pageModel.refreshing.value
    LaunchedEffect(refreshing) {
        if (refreshState.isAnimating != refreshing) {
            if (refreshing) {
                refreshState.animateToThreshold()
            } else {
                refreshState.animateToHidden()
            }
        }
    }
    LaunchedEffect(refreshState.isAnimating) {
        if (refreshState.isAnimating) {
            pageModel.refresh()
        }
    }
    return refreshState
}

/**
 * 获取Item类型
 */
private fun getItemType(item: Any): Int {
    if (item is IItemType) {
        return item.itemType
    }
    return IItemType.ITEM_TYPE_COMMON
}

/**
 * 获取item唯一标识
 */
private fun getItemKey(item: Any): Any {
    if (item is IItemKey) {
        return item.itemKey
    }
    // 默认使用json作为key
    // note: 这里会增加列表开销,尽量实现[IItemKey]
    return item.toJson(false)
}